#ifndef CXXOMFORT_CXXOLITERALS_LITERALS_HPP
#define CXXOMFORT_CXXOLITERALS_LITERALS_HPP
#include <cxxomfort/config.hpp>
#include <cxxomfort/base.hpp>
/**
 * @file
 * Support for emulation of literal suffixes. Of note this is done 
 * via a macro and can thus conflict with other stuff; to 
 * reduce clashing, this header must be included explicitly.
 *
 */

// Implementation basis:
//http://www.modernescpp.com/index.php/c-is-still-lazy

namespace cxxomfort { namespace literals {

// implementation of "suffix"-like function objects
namespace impl {

template <typename Dest, typename Derived>
struct affix_definition1 {
	typedef Dest return_type;
	CXXO_CONSTEXPR  Dest  operator() (const char* p) const CXXO_NOEXCEPT  { 
		return static_cast<Derived const*>(this)->operator()(p); 
	}
};

template <typename Dest>
struct affix_definition1<Dest,void> {
	typedef Dest return_type;
	CXXO_CONSTEXPR  Dest  operator() (const char* p) const CXXO_NOEXCEPT  { 
		return static_cast<Dest>(p);
	}
};

// Uses signature (2) in cppreference: T(unsigned long long int)
template <typename Dest, typename Derived>
struct affix_definition2 {
	typedef Dest return_type;
	CXXO_CONSTEXPR  Dest  operator() (unsigned long long int a) const CXXO_NOEXCEPT { 
		return static_cast<Derived const*>(this)->operator()(a); 
	}
};

template <typename Dest>
struct affix_definition2<Dest,void> {
	typedef Dest return_type;
	CXXO_CONSTEXPR  Dest  operator() (unsigned long long int a) const CXXO_NOEXCEPT { 
		return static_cast<Dest>(a); 
	}
};


template <typename D, typename Derived>
CXXO_CONSTEXPR inline static 
typename impl::affix_definition2<D,Derived>::return_type operator| 
(unsigned long long int v, impl::affix_definition2<D,Derived> const& A) CXXO_NOEXCEPT {
	return A(v);
}



// Uses signature (3) in cppreference: T(long double)

template <typename Dest, typename Derived>
struct affix_definition3 {
	typedef Dest return3_type;
	CXXO_CONSTEXPR  Dest  operator() (long double a) const CXXO_NOEXCEPT { 
		return static_cast<Derived const*>(this)->operator()(a); 
	}
};

template <typename Dest>
struct affix_definition3<Dest,void> {
	typedef Dest return3_type;
	CXXO_CONSTEXPR  Dest  operator() (long double a) const CXXO_NOEXCEPT { 
		return static_cast<Dest>(a); 
	}
};


template <typename D, typename Derived>
CXXO_CONSTEXPR inline static 
typename impl::affix_definition3<D,Derived>::return3_type operator| 
(long double v, impl::affix_definition3<D,Derived> const& A) CXXO_NOEXCEPT {
	return A(v);
}



// Uses signature (8) in cppreference: T(const char*, size_t)

template <typename Dest, typename Derived>
struct affix_definition8 {
	typedef Dest return8_type;
	template <size_t N>
	CXXO_CONSTEXPR  Dest  operator() (char const (&p) [N] ) const CXXO_NOEXCEPT { 
		return static_cast<Derived const*>(this)->operator()(p); 
	}
	/*
	CXXO_CONSTEXPR  Dest  operator() (char const* const p, size_t s) const CXXO_NOEXCEPT { 
		return static_cast<Derived const*>(this)->operator()(p,p+s); 
	}
	* */
};

template <typename Dest>
struct affix_definition8<Dest,void> {
	typedef Dest return8_type;
	template <size_t N>
	CXXO_CONSTEXPR  Dest  operator() (char const (&p)[N]) const CXXO_NOEXCEPT { 
		return Dest(p,p+N); 
	}
	CXXO_CONSTEXPR Dest  operator() (char const* const p, size_t s) const CXXO_NOEXCEPT {
		return Dest(p,p+s);
	}
	
};

// Uses signature (9) in cppreference: T(const wchar_t*, size_t)
template <typename Dest, typename Derived>
struct affix_definition9 {
	typedef Dest return9_type;
	template <size_t N>
	CXXO_CONSTEXPR  Dest  operator() (wchar_t const (&p) [N] ) const CXXO_NOEXCEPT { 
		return static_cast<Derived const*>(this)->operator()(p,p+N); 
	}
	/*
	CXXO_CONSTEXPR  Dest  operator() (wchar_t const* const p, size_t s) const CXXO_NOEXCEPT { 
		return static_cast<Derived const*>(this)->operator()(p,s); 
	}
	* */
};

template <typename Dest>
struct affix_definition9<Dest,void> {
	typedef Dest return9_type;
	template <size_t N>
	CXXO_CONSTEXPR  Dest  operator() (wchar_t const (&p) [N] ) const CXXO_NOEXCEPT { 
		return Dest(p,p+N);
	}
	CXXO_CONSTEXPR  Dest  operator() (wchar_t const* const p, size_t s) const CXXO_NOEXCEPT { 
		return Dest(p,p+s);
	}
};


// a simple exmaple of how to implement an affix
}

template <typename D, size_t N, typename Derived>
CXXO_CONSTEXPR inline static 
typename impl::affix_definition8<D,Derived>::return8_type operator| 
(char const (&v)[N] , impl::affix_definition8<D,Derived> const& A) CXXO_NOEXCEPT {
	return A(v);
}

template <typename D, size_t N, typename Derived>
CXXO_CONSTEXPR inline static 
typename impl::affix_definition9<D,Derived>::return9_type operator| 
(wchar_t const (&v)[N] , impl::affix_definition9<D,Derived> const& A) CXXO_NOEXCEPT {
	return A(v);
}



//
// When invoked in C++11 mode, generates a suffix operator
#if (CXXOMFORT_CXX_STD >= 2011)
	#define CXXO_GENERATE_AFFIX2_FOR(foo) \
constexpr typename decltype(foo)::return_type operator"" _##foo (unsigned long long v) { \
	return foo(v); \
} \

	#define CXXO_GENERATE_AFFIX8_FOR(foo) \
CXXO_CONSTEXPR14 typename decltype(foo)::return8_type operator"" _##foo (const char* v, size_t sz) { \
	return foo(static_cast<const char*>(v),sz); \
} \

	#define CXXO_GENERATE_AFFIX9_FOR(foo) \
CXXO_CONSTEXPR14 typename decltype(foo)::return9_type operator"" _##foo (const wchar_t* v, size_t sz) { \
	return foo(v,sz); \
} \

#else
	// in C++03 mode, we define these to just not do anything
	#define CXXO_GENERATE_AFFIX2_FOR(foo) enum {};
	#define CXXO_GENERATE_AFFIX8_FOR(foo) enum {};
	#define CXXO_GENERATE_AFFIX9_FOR(foo) enum {};

#endif


// a custom suffix that does a transformation

CXXO_CONSTEXPR const struct dbl_t
: public ::cxxomfort::literals::impl::affix_definition2<unsigned short, dbl_t> {
	// we override to double
	CXXO_CONSTEXPR return_type operator() (unsigned long long v) const CXXO_NOEXCEPT {
		return 2*v;
	}
} dbl;

CXXO_CONSTEXPR const struct hlf_t
: public ::cxxomfort::literals::impl::affix_definition2<unsigned short, hlf_t> {
	// we override to double
	CXXO_CONSTEXPR return_type operator() (unsigned long long v) const CXXO_NOEXCEPT {
		return v/2;
	}
} hlf;


// usage would be as such:



/*
 * c++03 / everywhere:   foo (-4 | zu); // calls foo(size_t)
 * c++14 onward      :   foo (-4_zu); // calls foo(size_t)
 * 
 */



} }


/*
 * ---
 * OLD IMPL
 * ---
 */

namespace cxxomfort {
/**
 * @page library:literals
 * 
 * The following literals are implemented by default:
 * 
 * * @ref sh (short)
 * * @ref ush (unsigned short)
 * * @ref s (std::string)
 * * @ref s (std::wstring)
 * 
 */

//! Namespace for literal operators emulation.
namespace literals {

namespace { // accessible only here

// base structure for a literals operator
struct literal_base {
};

template <typename T, typename Q>
struct literal_impl0: literal_base {
    friend CXXO_CONSTEXPR inline 
    T operator| (Q const& q, literal_impl0 const&) {
        return T(q);
    }
};

template <typename T, typename Q> 
struct literal_impl1 : literal_base {
    friend CXXO_CONSTEXPR inline 
    T operator | (Q const& q, literal_impl1 const&) {
        return T(q);
    }
};


template <typename T, typename Q>
struct literal_implD: literal_base {
    virtual T operator() (Q) const = 0;

    friend CXXO_CONSTEXPR inline 
    T operator| (Q const& q, literal_implD const& p) {
        return p(q);
    }

};


} // namespace{



// sh literal: converts to short
// ush literal: converts to unsigned short

/*
const struct : literal_impl1<short, int>{
} sh;

const struct : literal_impl1<unsigned short, unsigned int> {
} ush;
*/

namespace _ = cxxomfort::literals;


} // literals::
}

#define _l(L) | ::cxxomfort::literals::L 

// another way of doing it
#endif
